<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<title>OpenCV: Geometric Transformations of Images</title>
<link href="../../opencv.ico" rel="shortcut icon" type="image/x-icon" />
<link href="../../tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../jquery.js"></script>
<script type="text/javascript" src="../../dynsections.js"></script>
<script type="text/javascript" src="../../tutorial-utils.js"></script>
<link href="../../search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../search/searchdata.js"></script>
<script type="text/javascript" src="../../search/search.js"></script>
<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    extensions: ["tex2jax.js", "TeX/AMSmath.js", "TeX/AMSsymbols.js"],
    jax: ["input/TeX","output/HTML-CSS"],
});
//<![CDATA[
MathJax.Hub.Config(
{
  TeX: {
      Macros: {
          matTT: [ "\\[ \\left|\\begin{array}{ccc} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{array}\\right| \\]", 9],
          fork: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ \\end{array} \\right.", 4],
          forkthree: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ \\end{array} \\right.", 6],
          forkfour: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ #7 & \\mbox{#8}\\\\ \\end{array} \\right.", 8],
          vecthree: ["\\begin{bmatrix} #1\\\\ #2\\\\ #3 \\end{bmatrix}", 3],
          vecthreethree: ["\\begin{bmatrix} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{bmatrix}", 9],
          cameramatrix: ["#1 = \\begin{bmatrix} f_x & 0 & c_x\\\\ 0 & f_y & c_y\\\\ 0 & 0 & 1 \\end{bmatrix}", 1],
          distcoeffs: ["(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \\tau_x, \\tau_y]]]]) \\text{ of 4, 5, 8, 12 or 14 elements}"],
          distcoeffsfisheye: ["(k_1, k_2, k_3, k_4)"],
          hdotsfor: ["\\dots", 1],
          mathbbm: ["\\mathbb{#1}", 1],
          bordermatrix: ["\\matrix{#1}", 1]
      }
  }
}
);
//]]>
</script><script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js"></script>
<link href="../../doxygen.css" rel="stylesheet" type="text/css" />
<link href="../../stylesheet.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<!--#include virtual="/google-search.html"-->
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectlogo"><img alt="Logo" src="../../opencv-logo-small.png"/></td>
  <td style="padding-left: 0.5em;">
   <div id="projectname">OpenCV
   &#160;<span id="projectnumber">4.5.2</span>
   </div>
   <div id="projectbrief">Open Source Computer Vision</div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "../../search",false,'Search');
</script>
<script type="text/javascript" src="../../menudata.js"></script>
<script type="text/javascript" src="../../menu.js"></script>
<script type="text/javascript">
$(function() {
  initMenu('../../',true,false,'search.php','Search');
  $(document).ready(function() { init_search(); });
});
</script>
<div id="main-nav"></div>
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div id="nav-path" class="navpath">
  <ul>
<li class="navelem"><a class="el" href="../../d6/d00/tutorial_py_root.html">OpenCV-Python Tutorials</a></li><li class="navelem"><a class="el" href="../../d2/d96/tutorial_py_table_of_contents_imgproc.html">Image Processing in OpenCV</a></li>  </ul>
</div>
</div><!-- top -->
<div class="header">
  <div class="headertitle">
<div class="title">Geometric Transformations of Images </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><h2>Goals </h2>
<ul>
<li>Learn to apply different geometric transformations to images, like translation, rotation, affine transformation etc.</li>
<li>You will see these functions: <b><a class="el" href="../../da/d54/group__imgproc__transform.html#ga20f62aa3235d869c9956436c870893ae" title="Calculates a perspective transform from four pairs of the corresponding points. ">cv.getPerspectiveTransform</a></b></li>
</ul>
<h2>Transformations </h2>
<p>OpenCV provides two transformation functions, <b><a class="el" href="../../da/d54/group__imgproc__transform.html#ga0203d9ee5fcd28d40dbc4a1ea4451983" title="Applies an affine transformation to an image. ">cv.warpAffine</a></b> and <b><a class="el" href="../../da/d54/group__imgproc__transform.html#gaf73673a7e8e18ec6963e3774e6a94b87" title="Applies a perspective transformation to an image. ">cv.warpPerspective</a></b>, with which you can perform all kinds of transformations. <b><a class="el" href="../../da/d54/group__imgproc__transform.html#ga0203d9ee5fcd28d40dbc4a1ea4451983" title="Applies an affine transformation to an image. ">cv.warpAffine</a></b> takes a 2x3 transformation matrix while <b><a class="el" href="../../da/d54/group__imgproc__transform.html#gaf73673a7e8e18ec6963e3774e6a94b87" title="Applies a perspective transformation to an image. ">cv.warpPerspective</a></b> takes a 3x3 transformation matrix as input.</p>
<h3>Scaling</h3>
<p>Scaling is just resizing of the image. OpenCV comes with a function <b><a class="el" href="../../da/d54/group__imgproc__transform.html#ga47a974309e9102f5f08231edc7e7529d" title="Resizes an image. ">cv.resize()</a></b> for this purpose. The size of the image can be specified manually, or you can specify the scaling factor. Different interpolation methods are used. Preferable interpolation methods are <b><a class="el" href="../../da/d54/group__imgproc__transform.html#gga5bb5a1fea74ea38e1a5445ca803ff121acf959dca2480cc694ca016b81b442ceb">cv.INTER_AREA</a></b> for shrinking and <b><a class="el" href="../../da/d54/group__imgproc__transform.html#gga5bb5a1fea74ea38e1a5445ca803ff121a55e404e7fa9684af79fe9827f36a5dc1">cv.INTER_CUBIC</a></b> (slow) &amp; <b><a class="el" href="../../da/d54/group__imgproc__transform.html#gga5bb5a1fea74ea38e1a5445ca803ff121ac97d8e4880d8b5d509e96825c7522deb">cv.INTER_LINEAR</a></b> for zooming. By default, the interpolation method <b><a class="el" href="../../da/d54/group__imgproc__transform.html#gga5bb5a1fea74ea38e1a5445ca803ff121ac97d8e4880d8b5d509e96825c7522deb">cv.INTER_LINEAR</a></b> is used for all resizing purposes. You can resize an input image with either of following methods: </p><div class="fragment"><div class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</div><div class="line"><span class="keyword">import</span> cv2 <span class="keyword">as</span> cv</div><div class="line"></div><div class="line">img = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">cv.imread</a>(<span class="stringliteral">&#39;messi5.jpg&#39;</span>)</div><div class="line"></div><div class="line">res = <a class="code" href="../../da/d54/group__imgproc__transform.html#ga47a974309e9102f5f08231edc7e7529d">cv.resize</a>(img,<span class="keywordtype">None</span>,fx=2, fy=2, interpolation = cv.INTER_CUBIC)</div><div class="line"></div><div class="line"><span class="comment">#OR</span></div><div class="line"></div><div class="line">height, width = img.shape[:2]</div><div class="line">res = <a class="code" href="../../da/d54/group__imgproc__transform.html#ga47a974309e9102f5f08231edc7e7529d">cv.resize</a>(img,(2*width, 2*height), interpolation = cv.INTER_CUBIC)</div></div><!-- fragment --> <h3>Translation</h3>
<p>Translation is the shifting of an object's location. If you know the shift in the (x,y) direction and let it be \((t_x,t_y)\), you can create the transformation matrix \(\textbf{M}\) as follows:</p>
<p class="formulaDsp">
\[M = \begin{bmatrix} 1 &amp; 0 &amp; t_x \\ 0 &amp; 1 &amp; t_y \end{bmatrix}\]
</p>
<p>You can take make it into a Numpy array of type np.float32 and pass it into the <b><a class="el" href="../../da/d54/group__imgproc__transform.html#ga0203d9ee5fcd28d40dbc4a1ea4451983" title="Applies an affine transformation to an image. ">cv.warpAffine()</a></b> function. See the below example for a shift of (100,50): </p><div class="fragment"><div class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</div><div class="line"><span class="keyword">import</span> cv2 <span class="keyword">as</span> cv</div><div class="line"></div><div class="line">img = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">cv.imread</a>(<span class="stringliteral">&#39;messi5.jpg&#39;</span>,0)</div><div class="line">rows,cols = img.shape</div><div class="line"></div><div class="line">M = np.float32([[1,0,100],[0,1,50]])</div><div class="line">dst = <a class="code" href="../../da/d54/group__imgproc__transform.html#ga0203d9ee5fcd28d40dbc4a1ea4451983">cv.warpAffine</a>(img,M,(cols,rows))</div><div class="line"></div><div class="line"><a class="code" href="../../df/d24/group__highgui__opengl.html#gaae7e90aa3415c68dba22a5ff2cefc25d">cv.imshow</a>(<span class="stringliteral">&#39;img&#39;</span>,dst)</div><div class="line"><a class="code" href="../../d7/dfc/group__highgui.html#ga5628525ad33f52eab17feebcfba38bd7">cv.waitKey</a>(0)</div><div class="line"><a class="code" href="../../d7/dfc/group__highgui.html#ga6b7fc1c1a8960438156912027b38f481">cv.destroyAllWindows</a>()</div></div><!-- fragment --><p> <b>warning</b></p>
<p>The third argument of the <b><a class="el" href="../../da/d54/group__imgproc__transform.html#ga0203d9ee5fcd28d40dbc4a1ea4451983" title="Applies an affine transformation to an image. ">cv.warpAffine()</a></b> function is the size of the output image, which should be in the form of **(width, height)**. Remember width = number of columns, and height = number of rows.</p>
<p>See the result below:</p>
<div class="image">
<img src="../../translation.jpg" alt="translation.jpg"/>
<div class="caption">
image</div></div>
 <h3>Rotation</h3>
<p>Rotation of an image for an angle \(\theta\) is achieved by the transformation matrix of the form</p>
<p class="formulaDsp">
\[M = \begin{bmatrix} cos\theta &amp; -sin\theta \\ sin\theta &amp; cos\theta \end{bmatrix}\]
</p>
<p>But OpenCV provides scaled rotation with adjustable center of rotation so that you can rotate at any location you prefer. The modified transformation matrix is given by</p>
<p class="formulaDsp">
\[\begin{bmatrix} \alpha &amp; \beta &amp; (1- \alpha ) \cdot center.x - \beta \cdot center.y \\ - \beta &amp; \alpha &amp; \beta \cdot center.x + (1- \alpha ) \cdot center.y \end{bmatrix}\]
</p>
<p>where:</p>
<p class="formulaDsp">
\[\begin{array}{l} \alpha = scale \cdot \cos \theta , \\ \beta = scale \cdot \sin \theta \end{array}\]
</p>
<p>To find this transformation matrix, OpenCV provides a function, <b><a class="el" href="../../da/d54/group__imgproc__transform.html#gafbbc470ce83812914a70abfb604f4326" title="Calculates an affine matrix of 2D rotation. ">cv.getRotationMatrix2D</a></b>. Check out the below example which rotates the image by 90 degree with respect to center without any scaling. </p><div class="fragment"><div class="line">img = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">cv.imread</a>(<span class="stringliteral">&#39;messi5.jpg&#39;</span>,0)</div><div class="line">rows,cols = img.shape</div><div class="line"></div><div class="line"><span class="comment"># cols-1 and rows-1 are the coordinate limits.</span></div><div class="line">M = <a class="code" href="../../da/d54/group__imgproc__transform.html#gafbbc470ce83812914a70abfb604f4326">cv.getRotationMatrix2D</a>(((cols-1)/2.0,(rows-1)/2.0),90,1)</div><div class="line">dst = <a class="code" href="../../da/d54/group__imgproc__transform.html#ga0203d9ee5fcd28d40dbc4a1ea4451983">cv.warpAffine</a>(img,M,(cols,rows))</div></div><!-- fragment --><p> See the result:</p>
<div class="image">
<img src="../../rotation.jpg" alt="rotation.jpg"/>
<div class="caption">
image</div></div>
 <h3>Affine Transformation</h3>
<p>In affine transformation, all parallel lines in the original image will still be parallel in the output image. To find the transformation matrix, we need three points from the input image and their corresponding locations in the output image. Then <b><a class="el" href="../../da/d54/group__imgproc__transform.html#ga8f6d378f9f8eebb5cb55cd3ae295a999" title="Calculates an affine transform from three pairs of the corresponding points. ">cv.getAffineTransform</a></b> will create a 2x3 matrix which is to be passed to <b><a class="el" href="../../da/d54/group__imgproc__transform.html#ga0203d9ee5fcd28d40dbc4a1ea4451983" title="Applies an affine transformation to an image. ">cv.warpAffine</a></b>.</p>
<p>Check the below example, and also look at the points I selected (which are marked in green color): </p><div class="fragment"><div class="line">img = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">cv.imread</a>(<span class="stringliteral">&#39;drawing.png&#39;</span>)</div><div class="line">rows,cols,ch = img.shape</div><div class="line"></div><div class="line">pts1 = np.float32([[50,50],[200,50],[50,200]])</div><div class="line">pts2 = np.float32([[10,100],[200,50],[100,250]])</div><div class="line"></div><div class="line">M = <a class="code" href="../../da/d54/group__imgproc__transform.html#ga47069038267385913c61334e3d6af2e0">cv.getAffineTransform</a>(pts1,pts2)</div><div class="line"></div><div class="line">dst = <a class="code" href="../../da/d54/group__imgproc__transform.html#ga0203d9ee5fcd28d40dbc4a1ea4451983">cv.warpAffine</a>(img,M,(cols,rows))</div><div class="line"></div><div class="line">plt.subplot(121),plt.imshow(img),plt.title(<span class="stringliteral">&#39;Input&#39;</span>)</div><div class="line">plt.subplot(122),plt.imshow(dst),plt.title(<span class="stringliteral">&#39;Output&#39;</span>)</div><div class="line">plt.show()</div></div><!-- fragment --><p> See the result:</p>
<div class="image">
<img src="../../affine.jpg" alt="affine.jpg"/>
<div class="caption">
image</div></div>
 <h3>Perspective Transformation</h3>
<p>For perspective transformation, you need a 3x3 transformation matrix. Straight lines will remain straight even after the transformation. To find this transformation matrix, you need 4 points on the input image and corresponding points on the output image. Among these 4 points, 3 of them should not be collinear. Then the transformation matrix can be found by the function <b><a class="el" href="../../da/d54/group__imgproc__transform.html#ga20f62aa3235d869c9956436c870893ae" title="Calculates a perspective transform from four pairs of the corresponding points. ">cv.getPerspectiveTransform</a></b>. Then apply <b><a class="el" href="../../da/d54/group__imgproc__transform.html#gaf73673a7e8e18ec6963e3774e6a94b87" title="Applies a perspective transformation to an image. ">cv.warpPerspective</a></b> with this 3x3 transformation matrix.</p>
<p>See the code below: </p><div class="fragment"><div class="line">img = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">cv.imread</a>(<span class="stringliteral">&#39;sudoku.png&#39;</span>)</div><div class="line">rows,cols,ch = img.shape</div><div class="line"></div><div class="line">pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])</div><div class="line">pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])</div><div class="line"></div><div class="line">M = <a class="code" href="../../da/d54/group__imgproc__transform.html#gae66ba39ba2e47dd0750555c7e986ab85">cv.getPerspectiveTransform</a>(pts1,pts2)</div><div class="line"></div><div class="line">dst = <a class="code" href="../../da/d54/group__imgproc__transform.html#gaf73673a7e8e18ec6963e3774e6a94b87">cv.warpPerspective</a>(img,M,(300,300))</div><div class="line"></div><div class="line">plt.subplot(121),plt.imshow(img),plt.title(<span class="stringliteral">&#39;Input&#39;</span>)</div><div class="line">plt.subplot(122),plt.imshow(dst),plt.title(<span class="stringliteral">&#39;Output&#39;</span>)</div><div class="line">plt.show()</div></div><!-- fragment --><p> Result:</p>
<div class="image">
<img src="../../perspective.jpg" alt="perspective.jpg"/>
<div class="caption">
image</div></div>
 <h2>Additional Resources </h2>
<ol type="1">
<li>"Computer Vision: Algorithms and Applications", Richard Szeliski</li>
</ol>
<h2>Exercises </h2>
</div></div><!-- contents -->
<!-- HTML footer for doxygen 1.8.6-->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated on Fri Apr 2 2021 11:36:37 for OpenCV by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="../../doxygen.png" alt="doxygen"/>
</a> 1.8.13
</small></address>
<script type="text/javascript">
//<![CDATA[
addTutorialsButtons();
//]]>
</script>
</body>
</html>
